﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Bamboo.Core.TemplateEngine.Velocity;
using Bamboo.Core.Common;
using System.Reflection;
using BambooGenTool.Helper;
using System.Security.Policy;
using System.IO;

namespace BambooGenTool
{
    
    public partial class MainScreen : Form
    {
        private IList<Type> entityTypes;
        private GenerateUtil generateUtilObject = new GenerateUtil();
        public MainScreen()
        {
            InitializeComponent();
            txtOuputFolder.Text = Directory.GetCurrentDirectory();
        }
        private bool IsValidInputForGenerating()
        {
            if (string.IsNullOrEmpty(txtBLLNameSpace.Text))
            {
                MessageBox.Show("Please input namespace for Business Layer");
                txtBLLNameSpace.Focus();
                return false;
            }
            if (string.IsNullOrEmpty(txtDAONameSpace.Text))
            {
                MessageBox.Show("Please input namespace for Data Access Layer");
                txtDAONameSpace.Focus();
                return false;
            }
            if (string.IsNullOrEmpty(txtDTONameSpace.Text))
            {
                MessageBox.Show("Please input namespace for DTO Layer");
                txtDTONameSpace.Focus();
                return false;
            }
            if (chkGenUI.Checked && string.IsNullOrEmpty(txtUINameSpace.Text))
            {
                MessageBox.Show("Please input UI namespace for generating UI");
                txtUINameSpace.Focus();
                return false;
            }
            bool hasCheckSthToGen = chkGenDAO.Checked || chkGenerateBAL.Checked || chkGenerateDTO.Checked || chkGenUI.Checked;
            if (!hasCheckSthToGen)
            {
                MessageBox.Show("Please check type of classes you want to generate");
                return false;
            }
            return true;

        }
        private Type GetTypeFromClassName(string entityClassName)
        {
            if (entityTypes != null)
            {
                foreach (Type entityType in entityTypes)
                {
                    if (entityType.Name == entityClassName)
                    {
                        return entityType;
                    }
                }
            }
            return null;
        }
        private IList GetSelectedClasses()
        {
            IList selectedClasses = new ArrayList();
            foreach (KeyDataObject item in lstEntityClass.SelectedItems)
            {
                selectedClasses.Add(item.Key);
            }
            return selectedClasses;
        }
        #region Events
        private void OnGenMapping(object sender, EventArgs e)
        {
            IList selectedClasses = GetSelectedClasses();
            if (selectedClasses == null || selectedClasses.Count == 0)
            {
                MessageBox.Show("Please select class to generate config");
                return;
            }
            if (string.IsNullOrEmpty(txtAssemblyName.Text))
            {
                MessageBox.Show("Please input assembly name contains BLL, DAO");
                return;
            }
            string content = GenerateMapping(selectedClasses);
            txtMapping.Text = content;
        }
        private void OnCheckGenerateUI(object sender, EventArgs e)
        {
            txtUINameSpace.Enabled = chkGenUI.Checked;
        }
        private void btnGenerate_Click(object sender, EventArgs e)
        {
            IList selectedClasses = GetSelectedClasses();
            if (selectedClasses == null || selectedClasses.Count == 0)
            {
                MessageBox.Show("Please select class to generate");
                return;
            }
            if (!IsValidInputForGenerating())
            {
                return;
            }
            if (chkGenerateDTO.Checked)
            {
                GenerateDTO(selectedClasses);
            }
            if (chkGenDAO.Checked)
            {
                GenerateDataAccessLayer(selectedClasses);
            }
            if (chkGenerateBAL.Checked)
            {
                GenerateBusinessLayer(selectedClasses);
            }
            if (chkGenUI.Checked)
            {
                GenerateUI(selectedClasses);
            }
            MessageBox.Show("Code files are generated successfully");
        }

        private void btnLoadEntity_Click(object sender, EventArgs e)
        {
            if (!IsDLLInputValid())
            {
                return;
            }
            LoadEntityClassToList();
            LoadDefaultInputNameSpace();
        }
        private string GetParentNamespace(string namespaceValue)
        {
            int lastPositionOfDotChar = namespaceValue.LastIndexOf('.');
            if (lastPositionOfDotChar < 0)
            {
                return namespaceValue;
            }
            return namespaceValue.Substring(0, lastPositionOfDotChar);
        }
        private void LoadDefaultInputNameSpace()
        {
            string parentNameSpaceOfEntity = GetParentNamespace(txtEntityNameSpace.Text);
            txtDTONameSpace.Text = parentNameSpaceOfEntity + ".DTO";
            txtDAONameSpace.Text = parentNameSpaceOfEntity + ".DAO";
            txtBLLNameSpace.Text = parentNameSpaceOfEntity + ".Business";
            txtUINameSpace.Text = parentNameSpaceOfEntity + ".UI";
            txtAssemblyName.Text = parentNameSpaceOfEntity;

        }
        private void btnBrowseOutputFolder_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            DialogResult result = openFileDialog.ShowDialog();
            if (result == DialogResult.OK)
            {
                txtOuputFolder.Text = openFileDialog.FileName;
            }
        }

        private void btnBrowseDLLFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            DialogResult result = openFileDialog.ShowDialog();
            if (result == DialogResult.OK)
            {
                txtDLLFile.Text = openFileDialog.FileName;
            }
        }

        private void btnGenerateConfig_Click(object sender, EventArgs e)
        {
            IList selectedClasses = GetSelectedClasses();
            if (selectedClasses == null || selectedClasses.Count == 0)
            {
                MessageBox.Show("Please select class to generate config");
                return;
            }
            if (string.IsNullOrEmpty(txtAssemblyName.Text))
            {
                MessageBox.Show("Please input assembly name contains BLL, DAO");
                txtAssemblyName.Focus();
                return;
            }
            string content = GenerateSpringConfig(selectedClasses);
            txtSpringConfig.Text = content;
        }
        #endregion
        private void GenerateContentForSelectedClasses(IList selectedClasses, string templateFile, string relativeOutputFolder, string fileNamePattern)
        {
            foreach (string className in selectedClasses)
            {
                Type entityType = GetTypeFromClassName(className);
                GenerateContentFromEntity(entityType, templateFile, relativeOutputFolder, fileNamePattern);
            }
        }

        private void GenerateContentFromEntity(Type entityType, string templateFile, string relativeOutputFolder, string fileNamePattern)
        {
            INVelocityEngine engine = NVelocityEngineFactory.CreateNVelocityFileEngine(Application.StartupPath + "\\Templates", false);
            Hashtable param = CreateParam(entityType);
            try
            {
                string content = engine.Process(param, templateFile);
                string outputPath = txtOuputFolder.Text + "/" + relativeOutputFolder;
                if (!Directory.Exists(outputPath))
                {
                    Directory.CreateDirectory(outputPath);
                }
                string filePath = outputPath + "/" + string.Format(fileNamePattern, entityType.Name);
                SysUtil.WriteFile(filePath, content);
            }
            catch
            {
            }
        }
        private void GenerateUI(IList selectedClasses)
        {
            GenerateContentForSelectedClasses(selectedClasses, "EditInfoForm.tpl", "UI", "{0}EditInfoForm.cs");
            GenerateContentForSelectedClasses(selectedClasses, "ListForm.tpl", "UI", "{0}ListForm.cs");
        }

        private string GetContentFromTemplate(Type entityType, string templateFile)
        {
            INVelocityEngine engine = NVelocityEngineFactory.CreateNVelocityFileEngine(Application.StartupPath + "\\Templates", false);
            Hashtable param = CreateParam(entityType);
            try
            {
                return engine.Process(param, templateFile);
            }
            catch
            {
            }
            return "";
        }
        private Hashtable CreateParam(Type entityType)
        {
            Hashtable param = new Hashtable();
            param["entityType"] = entityType;
            param["genHelper"] = generateUtilObject;
            param["uiHelper"] = new UIGenerateHelper();
            param["assemblyName"] = txtAssemblyName.Text;
            param["entityClassName"] = entityType.Name;
            param["entityNameSpace"] = txtEntityNameSpace.Text;
            param["dtoNameSpace"] = txtDTONameSpace.Text;
            param["bllNameSpace"] = txtBLLNameSpace.Text;
            param["daoNameSpace"] = txtDAONameSpace.Text;
            param["uiNameSpace"] = txtUINameSpace.Text;
            IList<PropertyInfo> nonObjectPropertyList = generateUtilObject.GetAllNonObjectProperty(entityType);
            param["nonObjectPropertyList"] = nonObjectPropertyList;
            IList<PropertyInfo> objectPropertyList = generateUtilObject.GetAllObjectProperty(entityType);
            param["objectPropertyList"] = objectPropertyList;
            return param;
        }

        private void LoadEntityClassToList()
        {
            entityTypes = generateUtilObject.GetAllTypesOfNameSpace(txtEntityNameSpace.Text, txtDLLFile.Text);
            IList listData = new ArrayList();
            foreach (Type type in entityTypes)
            {
                listData.Add(new KeyDataObject(type.Name, type.Name));
            }
            lstEntityClass.DataSource = listData;
            lstEntityClass.DisplayMember = "Text";
            lstEntityClass.ValueMember = "Key";
        }
        private void GenerateBusinessLayer(IList selectedClasses)
        {
            GenerateContentForSelectedClasses(selectedClasses, "BusinessLayerObject.tpl", "Business", "{0}Service.cs");
        }
        
        private void GenerateDataAccessLayer(IList selectedClasses)
        {
            GenerateContentForSelectedClasses(selectedClasses, "DataAccessBaseObject.tpl", "DAO", "{0}BaseDAO.cs");
            GenerateContentForSelectedClasses(selectedClasses, "DataAccessObject.tpl", "DAO", "{0}DAO.cs");
        }

        private void GenerateDTO(IList selectedClasses)
        {
            GenerateContentForSelectedClasses(selectedClasses, "DataTransferObject.tpl", "DTO", "{0}DTO.cs");
        }

        private bool IsDLLInputValid()
        {
            if (string.IsNullOrEmpty(txtDLLFile.Text))
            {
                MessageBox.Show("Please input DLL file");
                txtDLLFile.Focus();
                return false;
            }
            if (string.IsNullOrEmpty(txtEntityNameSpace.Text))
            {
                MessageBox.Show("Please input entity namespace");
                txtEntityNameSpace.Focus();
                return false;
            }
            return true;

        }

        private string GenerateSpringConfig(IList selectedClasses)
        {
            string result = "";
            foreach (string className in selectedClasses)
            {
                Type entityType = GetTypeFromClassName(className);
                result += GetContentFromTemplate(entityType, "SpringConfig.tpl");
            }
            return result;
        }

        
        private string GenerateMapping(IList selectedClasses)
        {
            string result = "";
            foreach (string className in selectedClasses)
            {
                Type entityType = GetTypeFromClassName(className);
                result += GetContentFromTemplate(entityType, "Mapping.tpl"); 
            }
            return result;
        }
    }
}
